home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / msdos / raytrace / pov / gen / povclk / envunit.pas < prev    next >
Pascal/Delphi Source File  |  1979-12-31  |  23KB  |  865 lines

  1. unit EnvUnit; {                 Version 2.8                      88/11/07
  2.  
  3. Handy little routines to simplify using the environment string.
  4.  
  5. See the example program ENVTEST.PAS, for hints on how to use this unit.
  6.  
  7. MOST LIKELY TO BE USED:   1) FFind - search the path for a named file and
  8.                                      return the fully qualified file name
  9.                                      if it is found.
  10.  
  11.                           2) PathTo - search the path for a named file;
  12.                                       return the path to that file if found
  13.  
  14.                           3) ParamStr - the complete parameter string
  15.  
  16.  
  17. This program is hereby donated to the public domain. It may be freely copied,
  18. used & modified without charge or fee.
  19.  
  20. Author        :  Mike Babulic
  21.                  3827 Charleswood Dr. N.W.
  22.                  Calgary, Alberta
  23.                  CANADA
  24.                  T2L 2C7
  25. Compuserve ID :  72307,314
  26.  
  27.  
  28. Modification Log:
  29. -----------------
  30.   88/11/07 - Version 2.8 - EnvStrPtr changed so root environment could be
  31.              found in DOS 2.0-3.2. Offset $2C from the root PSP is 0000 in
  32.              these early DOS's, so an alternative method of finding the
  33.              envirinment must be used. (see Dr Dobb's Journal, Dec.88, p.57)
  34. }
  35.  
  36.  
  37. interface
  38.  
  39. uses Dos;
  40.  
  41.  
  42. {$IFDEF VER40}   {These objects are already in TP Version 5's Dos Unit}
  43.                  {I've included them so you can upgrade gracefully}
  44.  
  45. type
  46.    PathStr = string[79];
  47.    DirStr  = string[67];
  48.    NameStr = string[8];
  49.    ExtStr  = string[4];
  50.  
  51. function DosVersion: word;  { lo = version (ex. 3);  hi = fraction (ex. .2) }
  52.  
  53. function EnvCount: integer;              {number of Environment Strings}
  54. function EnvStr(Index:integer): string;  {get Env. String number index}
  55. function GetEnv(EnvVar:string): string;  {get Env. String named by EnvVar}
  56.  
  57. function FExpand(Path:PathStr):PathStr;
  58.   {expand the path to a fully qualified file name}
  59. function FSearch(Path:PathStr;DirList:string):PathStr;
  60.    {Search DirList (paths separated by ";") for Path & return full name of
  61.     this file}
  62. procedure FSplit(Path:PathStr; var Dir:DirStr; var Name:NameStr; var Ext:ExtStr);
  63. {$ENDIF}
  64.  
  65.  
  66.  
  67.   var   MyPath : string;        {Path & Name of the running program}
  68.         MyDir  : DirStr;
  69.         MyName : NameStr;
  70.         MyExt  : ExtStr;
  71.  
  72.  
  73.   function DOS_Version: integer;
  74.       {Returns the version of DOS being used (ex. 302 is DOS 3.2)}
  75.  
  76.  
  77.   function ParamString: String;
  78.       {Returns the complete parameter string}
  79.  
  80.   function EnvStrPtr:Pointer;
  81.       {Point to environment strings}
  82.  
  83.   function EnvSize:LongInt;
  84.       {Size of the current environment in bytes}
  85.  
  86.   function MaxEnvSize:LongInt;
  87.       {Maximum size of the current environment in bytes}
  88.  
  89.  
  90.   var PSP : word;  {Program Segment Prefix;  initially = PrefixSeg}
  91.  
  92.   function ProgPath: PathStr;    {Path to program owning current PSP}
  93.   function ProgDir:  DirStr;        {Directory of program owning current PSP}
  94.   function ProgName: NameStr;       {Name of program owning current PSP}
  95.   function ProgExt:  ExtStr;        {Extension of program owning current PSP}
  96.  
  97.   procedure UseMyPSP;
  98.       {Use the program's PSP to find the environment}
  99.   procedure UseParentPSP;
  100.       {Use the parent of the current PSP to find the environment}
  101.   procedure UseRootPSP;
  102.       {Use the parent of the current PSP to find the environment}
  103.  
  104.  
  105.   procedure DelEnv(name:String);
  106.       {delete the named string from the current environment}
  107.  
  108.    function SetEnv(name,env:String):boolean;
  109.       {set the named environment string to env}
  110.  
  111.    function SetPath(path:String):boolean;
  112.       {set the environment "PATH=" string to path}
  113.  
  114.  
  115.   function FirstEnv:String;
  116.       {Get the First Environment string}
  117.   function NextEnv:String;
  118.       {Get the Next Environment string}
  119.   procedure SkipEnv;
  120.       {Skip the Next Environment string}
  121.   function EOEnv:Boolean;
  122.      {True if End Of Environment}
  123.  
  124.  
  125.   function GetEnvPtr(name:String):Pointer;
  126.       {return a pointer to the named environment variable's string}
  127.  
  128.  
  129.   function FirstNamed(name,delim:String):String;
  130.      {Get the first string in an the named environment specification
  131.          eg. If name = 'PATH' and delim = ';' then get the first path string
  132.              "Path" strings are delimited by semicolins: ";" }
  133.   function NextNamed:String;
  134.      {Get the next string in an environment specification}
  135.   function EONamed:Boolean;
  136.      {True if end of environment specification}
  137.  
  138.  
  139.   function FirstPath:String;
  140.      {Almost the same as Firstnamed('PATH',';'), but appends a '\' to the
  141.       string if needed}
  142.   function NextPath:String;
  143.  
  144. {File Utilities}
  145.  
  146.   const AllowWildcards : boolean = TRUE;
  147.      {Used by FileExists and routines that depend on it (PathTo, FFind).
  148.       If TRUE these functions will allow wildcard characters in a file name}
  149.  
  150.   function ContainsWildcards(filename:string):boolean;
  151.      {True if filename contains wildcard characters}
  152.  
  153.  
  154.   function PathTo(filename:string):string;
  155.      {Searches the environment PATH and returns a path to the named file.
  156.         Check the current directory,
  157.         then search the environment PATH,
  158.         then check the directory containing the calling program (MyDir).
  159.         If the file is still not found, return a null string ('')}
  160.  
  161.  
  162.   const  FFindErr = '.';
  163.  
  164.   function FFind(filename:string):string;
  165.      {Find the File called "filename".
  166.         Check the current directory,
  167.         then search the environment PATH,
  168.         then check the directory containing the calling program (MyDir).
  169.         - if "filename" is found return the fully qualified file name
  170.           of the filename.
  171.         - if "filename" is NOT found then return FFindErr.
  172.           - a period is returned because if you write something like:
  173.                 Assign(aFile,FFind('MISSING.TXT'));
  174.                 Reset(aFile);
  175.             and FFind returned '' when it failed then aFile would be assigned
  176.             to the standard INPUT file (usually the keyboard)! }
  177.  
  178. {misc}
  179.   function  FileExists(name:string):Boolean;      {True if named file exists}
  180.   procedure PtrInc(var p:Pointer; n: Longint);    {Increment pointer by n}
  181.   function  PtrDiff(p1,p2:Pointer):Longint;       {p1-p2 in Bytes}
  182.   function  UpperStr(s:string):string;            {string to uppercase}
  183.  
  184.  
  185. {----------------------------------------------------------------------------}
  186.  
  187. implementation
  188.  
  189.   type pointr = record  lo,hi: word  end;
  190.  
  191.   procedure PtrInc(var p:Pointer; n: Longint);   {Increment pointer by n}
  192.     var
  193.        pt : pointr   absolute  p;
  194.        c  : pointr   absolute  n;
  195.     begin
  196.       n := pt.lo + n;
  197.       pt.hi := (n AND $FFFF0000) shr 4 + pt.hi;
  198.       pt.lo := c.lo;
  199.     end;
  200.  
  201.   function PtrDiff(p1,p2:pointer): LongInt;
  202.     var
  203.        a : pointr   absolute  p1;
  204.        b : pointr   absolute  p2;
  205.     begin
  206.       PtrDiff := (a.hi-b.hi) shl 4 + (a.lo-b.lo)
  207.     end;
  208.  
  209.   function  UpperStr(s:string):string;            {string to uppercase}
  210.     var i : integer;
  211.     begin
  212.       for i := 1 to length(s) do
  213.         UpperStr[i] := upcase(s[i]);
  214.       Upperstr[0] := s[0];
  215.     end;
  216.  
  217.  
  218. {-----------------------------------------------------------------------------}
  219.  
  220.  
  221.  
  222.   type WordP = ^word;
  223.  
  224.        MCB = packed record
  225.          kind   : char; {is 'M' or 'Z'}
  226.          PID    : word;
  227.          PCount : word; {# of paragraphs}
  228.          end;
  229.  
  230.        MCBPtr = ^MCB;
  231.  
  232.  
  233.   function EnvSeg : word;    {Segment containing the environment}
  234.     var
  235.       ESeg : word;
  236.       done,found   : boolean;
  237.     begin
  238.       ESeg := WordP(Ptr(PSP,$2C))^;
  239.       if ESeg = 0 then begin {DOS 2.0-3.2 root zeros this pointer, so..}
  240.         ESeg := Pred(PSP);   {hunt through the MCB chain for ESeg}
  241.         repeat
  242.           ESeg := ESeg + MCBPtr(Ptr(ESeg,0))^.PCount + 1;
  243.           with MCBPtr(Ptr(ESeg,0))^ do begin
  244.             found  := (PID=PSP);
  245.             done   := found         {found it!}
  246.                    or (PID<>0)      {past command.com's storage}
  247.                    or (kind='Z');   {end of the chain}
  248.           end;
  249.         until done;
  250.         Eseg := Succ(ESeg);
  251.         if not found then ESeg := 0;
  252.       end;
  253.       EnvSeg := ESeg;
  254.     end;
  255.  
  256.  
  257.   function EnvStrPtr:Pointer;
  258.     begin
  259.       EnvStrPtr := Ptr(EnvSeg,0);
  260.     end;
  261.  
  262.   function EnvSize: LongInt;
  263.     var  p1,p2 : ^char;
  264.     begin
  265.       p1 := EnvStrPtr;
  266.       p2 := p1;
  267.       {move past environment strings}
  268.         repeat
  269.           while p2^<>#0 do begin
  270.             PtrInc(Pointer(p2),1);
  271.           end;
  272.           PtrInc(Pointer(p2),1);
  273.         until p2^=#0;
  274.       if Dos_Version >= 300 then begin  {skip program name}
  275.         PtrInc(Pointer(p2),3);
  276.         while p2^<>#0 do
  277.           PtrInc(Pointer(p2),1);
  278.         PtrInc(Pointer(p2),1);
  279.       end;
  280.       EnvSize := PtrDiff(p2,p1)+1;
  281.     end;
  282.  
  283.   function MaxEnvSize:LongInt;
  284.     begin
  285.       MaxEnvSize := MCBPtr(Ptr(Pred(EnvSeg),0))^.PCount  shl  4;
  286.     end;
  287.  
  288.   procedure UseMyPSP;
  289.     begin
  290.       PSP := PrefixSeg;
  291.     end;
  292.  
  293.   Procedure UseParentPSP;
  294.     begin
  295.       PSP := WordP(Ptr(PSP,$16))^;
  296.     end;
  297.  
  298.   Procedure UseRootPSP;
  299.     var oldPSP : word;
  300.     begin
  301.       repeat
  302.         oldPSP := PSP;
  303.         UseParentPSP;
  304.       until PSP=oldPSP;
  305.     end;
  306.  
  307.  
  308.  
  309.  
  310. {-----------------------------------------------------------------------------}
  311.  
  312.   Type ASCIIz = array [0..255] of char;
  313.        ASCIIptr = ^ASCIIz;
  314.  
  315.   function LenZ(var c:ASCIIz): Word;  {length of ASCIIz string}
  316.     var i: Word;
  317.     begin
  318.       for i := 0 to MaxInt do
  319.         if c[i]=#0 then begin
  320.           LenZ := i;
  321.           exit;
  322.         end;
  323.       LenZ := MaxInt;
  324.     end;
  325.  
  326.   function StrZn(var c:ASCIIz;MaxLen:integer):string;
  327.     label done;
  328.     var i,j: integer;
  329.     begin
  330.       MaxLen := MaxLen-1;
  331.       for i := 0 to MaxLen do begin
  332.        if c[i]=#0 then goto done;
  333.         StrZn[i+1] := c[i];
  334.       end;
  335.       i := MaxLen+1;
  336.       done: StrZn[0] := chr(i);
  337.     end;
  338.  
  339.   function StrZ(var c:ASCIIz):string;
  340.     const MaxLen = 254;
  341.     label done;
  342.     var i,j: integer;
  343.     begin
  344.       for i := 0 to MaxLen do begin
  345.        if c[i]=#0 then goto done;
  346.         StrZ[i+1] := c[i];
  347.       end;
  348.       i := MaxLen+1;
  349.       done: StrZ[0] := chr(i);
  350.     end;
  351.  
  352.  
  353.   function ToDelim(d:string; var s:string):integer;
  354.     var i:integer;
  355.     begin
  356.       i := pos(d,s);    {length to first delimiter}
  357.       if i>0 then
  358.         s[0] := chr(i-1)
  359.       else
  360.         i := length(s);
  361.       ToDelim := i;
  362.     end;
  363.  
  364.  
  365. {----------------------------------------------------------------------------}
  366.  
  367.  
  368. function ParamString: String;
  369.   type StrPtr = ^String;
  370.   begin
  371.     ParamString := StrPtr(Ptr(PrefixSeg,$80))^;
  372.   end;
  373.  
  374.  
  375. {----------------------------------------------------------------------------}
  376.  
  377.  
  378.   var EnvPtr : ASCIIptr;
  379.  
  380.   function FirstEnv:String;
  381.     var s: string[255];
  382.         i: integer;
  383.     begin
  384.       EnvPtr := EnvStrPtr;
  385.       FirstEnv := NextEnv;
  386.     end;
  387.  
  388.   function NextEnv:String;
  389.     var s: string;
  390.         i: integer;
  391.     begin
  392.       if EOEnv then
  393.         NextEnv := ''
  394.       else begin
  395.         s := StrZ(EnvPtr^);
  396.         i := ToDelim(#0,s);
  397.         PtrInc(Pointer(EnvPtr),i+1);
  398.         NextEnv := s;
  399.       end;
  400.     end;
  401.  
  402.   procedure SkipEnv;
  403.     var i : integer;
  404.     begin
  405.       for i := 1 to MaxInt do
  406.         if EnvPtr^[i]=#0 then begin
  407.           PtrInc(Pointer(EnvPtr),i+1);
  408.           exit
  409.         end;
  410.     end;
  411.  
  412.   function GetEnvPtr(name:string):Pointer;
  413.     var i : integer;
  414.     begin
  415.       for i := 1 to length(name) do name[i] := upcase(name[i]);
  416.       name := name + '=';
  417.       EnvPtr := EnvStrPtr;
  418.       repeat
  419.         if strZn(EnvPtr^,length(name)) = name then begin
  420.           GetEnvPtr := EnvPtr;
  421.           exit;
  422.         end;
  423.         SkipEnv;
  424.       until EoEnv;
  425.       GetEnvPtr := EnvPtr;
  426.     end;
  427.  
  428.    function EOEnv:Boolean;
  429.      begin
  430.        EOEnv := (EnvPtr^[0]=#0);
  431.      end;
  432.  
  433. {----------------------------------------------------------------------------}
  434.  
  435.    procedure DelEnv(name:String);
  436.      var p1,p2 : ASCIIptr;
  437.      begin
  438.        p1 := GetEnvPtr(name);
  439.        if not EoEnv then begin
  440.          SkipEnv;
  441.          p2 := EnvPtr;
  442.          move(p2^,p1^, EnvSize - PtrDiff(p2,EnvStrPtr));
  443.        end;
  444.      end;
  445.  
  446.    function SetEnv(name,env:String):boolean;
  447.      var p1 : ASCIIptr;
  448.          l  : LongInt;
  449.      begin
  450.        DosError := 0;
  451.        {Null strings remove the variable from the environment}
  452.          if env='' then begin
  453.            DelEnv(name);
  454.            SetEnv := True;
  455.            exit;
  456.          end;
  457.        SetEnv := FALSE;
  458.        {Make sure env isn't too big}
  459.          p1 := GetEnvPtr(name); {null string if not found}
  460.          l  := LenZ(p1^);
  461.          if l=0 then l := -1; {trick to add 1 to the new length}
  462.          if MaxEnvSize < length(name)+1+length(env) + EnvSize - l then begin
  463.            DosError := 8; {Not Enough Memory}
  464.            exit;
  465.          end;
  466.        DelEnv(name);
  467.        {insert new string}
  468.          env := UpperStr(name)+'='+env;
  469.          {go to end of environment}
  470.            EnvPtr := EnvStrPtr;
  471.            while not EoEnv do SkipEnv;
  472.          {make room}
  473.            p1 := EnvPtr;  PtrInc(Pointer(p1),length(env)+1);
  474.            move(EnvPtr^,p1^,EnvSize-PtrDiff(EnvPtr,EnvStrPtr)-1);
  475.          {move in data}
  476.            move(env[1],EnvPtr^,length(env));
  477.            ASCIIptr(EnvPtr)^[length(env)] := #0;
  478.        SetEnv := TRUE;
  479.      end;
  480.  
  481.    function SetPath(path:String):boolean;
  482.      begin
  483.        SetPath := SetEnv('PATH',UpperStr(path));
  484.      end;
  485.  
  486. {----------------------------------------------------------------------------}
  487.  
  488.  
  489.   var namePtr : ASCIIptr;
  490.       dummy  : LongInt;
  491.       namedDelim : string;
  492.  
  493.   function EONamed:Boolean;
  494.     begin
  495.       EONamed := (namePtr^[0]=#0);
  496.     end;
  497.  
  498.   function FirstNamed(name,delim:String):string;
  499.     var
  500.         s: string;
  501.         i: integer;
  502.     begin
  503.       namePtr    := GetEnvPtr(name);
  504.       namedDelim := delim;
  505.       if EoEnv then begin
  506.         FirstNamed := '';
  507.         exit;
  508.       end;
  509.       PtrInc(Pointer(namePtr),length(name)+1); {skip past the name}
  510.       s := StrZ(namePtr^);
  511.       i := ToDelim(delim,s);
  512.       FirstNamed := s;
  513.       PtrInc(Pointer(namePtr),length(s)+1);
  514.     end;
  515.  
  516.   function NextNamed:string;
  517.     var
  518.         s: string;
  519.         i: integer;
  520.     begin
  521.       if EONamed then begin
  522.         NextNamed := '';
  523.         end
  524.       else begin
  525.         s := StrZ(namePtr^);
  526.         i := ToDelim(NamedDelim,s);
  527.         PtrInc(Pointer(namePtr),i);
  528.         NextNamed := s;
  529.       end;
  530.     end;
  531.  
  532.  
  533.  
  534. {-----------------------------------------------------------------------------}
  535.  
  536.  
  537.   var  FileInfo :  SearchRec;
  538.  
  539.  
  540.   function ContainsWildcards(filename:string):boolean;
  541.     begin
  542.       ContainsWildcards := ((pos('?',filename)>0) or (pos('*',filename)>0))
  543.     end;
  544.  
  545.  
  546.   function FileExists(name:string):Boolean;
  547.     begin
  548.       if (not AllowWildcards) and ContainsWildcards(name) then begin
  549.         FileExists := FALSE;
  550.         exit;
  551.       end;
  552.       FindFirst(Name,0,FileInfo);
  553.       FileExists := (DosError=0);
  554.     end;
  555.  
  556.  
  557. {-----------------------------------------------------------------------------}
  558.  
  559. {----------------------------------------------------------------------------}
  560.  
  561.   function DirDelim(s:String):String;
  562.     var i: integer;
  563.         c: char;
  564.     begin
  565.       DirDelim := '';
  566.       i := length(s);
  567.       while (i>0) and (s[i]=' ') do i := pred(i);
  568.       if i<=0 then exit;
  569.       s[0] := chr(i);
  570.       if (i<1) or not (s[i] IN [':','\']) then
  571.         s := s + '\';
  572.       DirDelim := s;
  573.     end;
  574.  
  575.   function FirstPath: String;
  576.     begin
  577.       FirstPath := DirDelim(FirstNamed('PATH',';'));
  578.     end;
  579.  
  580.   function NextPath: String;
  581.     begin
  582.       NextPath := DirDelim(NextNamed);
  583.     end;
  584.  
  585.   function SpecifiesDrive(var filename:string):boolean;
  586.     begin
  587.       SpecifiesDrive := (filename[2]=':') and (length(filename)>1)
  588.     end;
  589.  
  590.  
  591.   function PathTo(filename:string):string;
  592.     var path: string;
  593.         found: boolean;
  594.     procedure CurrentPath;
  595.       begin
  596.         if FileExists(path+filename) then begin   {Check Current Directory}
  597.           if  (filename[1]='\') then begin  {root directory}
  598.             found := TRUE;
  599.            end
  600.           else begin
  601.             if SpecifiesDrive(path) then
  602.               GetDir(ord('A')-ord(upcase(path[1]))+1,path)
  603.             else
  604.               GetDir(0,path);
  605.             found := FileExists(path+filename);
  606.           end;
  607.           path := DirDelim(path);
  608.         end;
  609.       end;
  610.     begin
  611.       found := FALSE;
  612.       if filename<>'' then begin
  613.         if SpecifiesDrive(filename) then begin
  614.           path     := Copy(filename,1,2);
  615.           filename := Copy(filename,3,SizeOf(FileName));
  616.           CurrentPath;                       {Check the Named Disk Drive}
  617.         end;
  618.         if not found then begin
  619.           path := '';
  620.           CurrentPath;                       {Check the Default Path}
  621.         end;
  622.         if (not found) and (Copy(filename,1,1)<>'\') then begin
  623.           path  := FirstPath;                {Check the Path}
  624.           found := FileExists(path+filename);
  625.           while not (EONamed or found) do begin
  626.             path  := NextPath;
  627.             found := FileExists(path+filename);
  628.           end;
  629.         end;
  630.         if not found then begin               {Check the Program's Directory}
  631.           found := FileExists(MyDir+filename);
  632.           if found then path := MyDir;
  633.         end;
  634.         if found then
  635.           PathTo := path
  636.         else
  637.           PathTo := '';
  638.       end;
  639.     end;
  640.  
  641.   function FFind(filename:string):string;
  642.     var p : string;
  643.         d : DirStr;
  644.         n : NameStr;
  645.         x : ExtStr;
  646.     begin
  647.       p := PathTo(filename);
  648.       if p<>'' then
  649.         if SpecifiesDrive(filename) then
  650.           FFind := FExpand(p+copy(filename,3,255))
  651.         else
  652.           FFind := FExpand(p+filename)
  653.       else if FileExists(filename) then
  654.         FFind := FExpand(filename)
  655.       else
  656.         FFind := FFindErr;
  657.     end;
  658.  
  659.  
  660.  
  661.   function DOS_Version: integer;
  662.       {Returns the version of DOS being used}
  663.     var r : registers;
  664.     begin
  665.       r.ax := $3000;
  666.       MsDos(r);
  667.       with r do
  668.         DOS_Version := al * 100 + ah
  669.     end;
  670.  
  671.  
  672. {-----------------------------------------------------------------------------}
  673.  
  674.   var
  675.       pPath : string;
  676.       pDir  : DirStr;
  677.       pName : NameStr;
  678.       pExt  : ExtStr;
  679.  
  680.   procedure GetPName;
  681.     var
  682.       c : ^char;
  683.       i : word;
  684.     begin
  685.       if DOS_Version<300 then begin {Only for DOS 3.x and greater}
  686.         pPath := '';
  687.         pName := '';
  688.        end
  689.       else begin
  690.         c := EnvStrPtr;
  691.         {Skip to the end of the Environment}
  692.           repeat
  693.             while c^<>#0 do
  694.               PtrInc(pointer(c),1);
  695.             PtrInc(pointer(c),1);
  696.           until c^=#0;
  697.           PtrInc(Pointer(c),3);
  698.         pPath := FExpand(StrZ(AsciiPtr(c)^));
  699.         FSplit(pPath,pDir,pName,pExt);
  700.       end;
  701.     end;
  702.  
  703.  
  704.  
  705.   function ProgPath: PathStr;    {Path to program owning current PSP}
  706.     begin
  707.       GetPName;  ProgPath := pPath;
  708.     end;
  709.  
  710.   function ProgDir:  DirStr;        {Directory of program owning current PSP}
  711.     begin
  712.       GetPName;  ProgDir := pDir;
  713.     end;
  714.  
  715.   function ProgName: NameStr;       {Name of program owning current PSP}
  716.     begin
  717.       GetPName;  ProgName := pName;
  718.     end;
  719.  
  720.   function ProgExt:  ExtStr;        {Extension of program owning current PSP}
  721.     begin
  722.       GetPName;  ProgExt := pExt;
  723.     end;
  724.  
  725.  
  726. {-----------------------------------------------------------------------------}
  727.  
  728. {$IFDEF VER40}  {These objects are already in TP Version 5's Dos Unit}
  729.  
  730.  
  731. function DosVersion: word;  { lo = version (ex. 3);  hi = fraction (ex. .2) }
  732.     var r : registers;
  733.     begin
  734.       r.ax := $3000;
  735.       MsDos(r);
  736.       DOSVersion := r.ax;
  737.     end;
  738.  
  739.  
  740. function EnvCount: integer;              {number of Environment Strings}
  741.   var i: integer;
  742.   begin
  743.     UseMyPSP;
  744.     EnvPtr := EnvStrPtr;
  745.     i := 0;
  746.     while not EoEnv do begin
  747.       SkipEnv;
  748.       i := succ(i);
  749.     end;
  750.     EnvCount := i;
  751.   end;
  752.  
  753.  
  754. function EnvStr(Index:integer): string;  {get Env. String number index}
  755.   begin
  756.     UseMyPSP;
  757.     EnvPtr := EnvStrPtr;
  758.     while (index>1) and not EoEnv do begin
  759.       SkipEnv;
  760.       index := pred(index);
  761.     end;
  762.     if index = 1 then
  763.       EnvStr := NextEnv
  764.     else
  765.       EnvStr := '';
  766.   end;
  767.  
  768.  
  769. function GetEnv(EnvVar:string): string;  {get Env. String named by EnvVar}
  770.   begin
  771.     GetEnv := FirstNamed(EnvVar,#0);
  772.   end;
  773.  
  774.  
  775. function FExpand(Path:PathStr):PathStr;
  776.   var
  777.     i : integer;
  778.     old: PathStr;
  779.   begin
  780.     FSplit(path,pDir,pName,pExt);
  781.     if length(pDir)=0 then
  782.       GetDir(0,pDir)
  783.     else begin
  784.       if pDir[length(pDir)]='\' then  pDir[0] := chr(length(pDir)-1);
  785.       GetDir(0,old);
  786.       ChDir(pDir);
  787.       GetDir(0,pDir);
  788.       ChDir(old);
  789.     end;
  790.     path := pName+pExt;
  791.     for i := 1 to length(path) do path[i] := UpCase(path[i]);
  792.     FExpand := pDir+'\'+path;
  793.   end;
  794.  
  795.  
  796.   function FSearch(Path:PathStr;DirList:string):PathStr;
  797.     var dir: string;
  798.         i: integer;
  799.         found: boolean;
  800.     procedure NextDir;
  801.       var j : integer;
  802.       begin
  803.         i := succ(i);  j := i;
  804.         while (j<length(DirList)) and (DirList[j]<>';') do j := succ(j);
  805.         Dir := DirDelim(Copy(Dirlist,i,j-i))+Path;
  806.         i := j;
  807.       end;
  808.     begin
  809.       FSearch := '';
  810.       if Path<>'' then begin
  811.         found := FileExists(path);       {Check Current Directory}
  812.         if Found then
  813.           Dir := Path
  814.         else begin                       {Check DirList}
  815.           i := 0;
  816.           repeat
  817.             NextDir;
  818.             found := FileExists(Dir);
  819.           until (i>=length(DirList)) or found;
  820.         end;
  821.         if found then
  822.           FSearch := Dir;
  823.       end;
  824.     end;
  825.  
  826.  
  827. procedure FSplit(Path:PathStr; var Dir:DirStr; var Name:NameStr; var Ext:ExtStr);
  828.   var i,j : integer;
  829.       done : boolean;
  830.   begin
  831.     Dir  := '';  Name := '';  Ext := '';
  832.     if Path='' then exit;
  833.     if Path[length(Path)]='.' then begin
  834.       Dir := Path;
  835.       if length(Path)=1 then exit;
  836.       if Path[length(Path)-1] in ['.','\'] then exit;
  837.       Dir := '';
  838.     end;
  839.     i := length(Path);  j := 0;  done := FALSE;
  840.     while (i>0) and (j<sizeof(Ext)) and not done do begin
  841.       done := (Path[i]='.');
  842.       if done then
  843.         Ext := Copy(Path,i,j+1);
  844.       j := succ(j);
  845.       i := pred(i);
  846.     end;
  847.     i := length(Path) - length(Ext);  j := i;
  848.     while (i>0) and not (Path[i] in [':','\']) do  i := pred(i);
  849.     Name := Copy(Path,i+1,j-i);
  850.     Dir := Copy(Path,1,i);
  851.   end;
  852. {$ENDIF}
  853.  
  854.  
  855. {-----------------------------------------------------------------------------}
  856.  
  857.   begin
  858.     UseMyPSP;
  859.     EnvPtr := EnvStrPtr;
  860.     dummy := 0;
  861.     namePtr := @dummy;
  862.     GetPName;
  863.     MyPath := pPath;
  864.     MyDir := pDir;  MyName := pName;  MyExt := pExt;
  865.   end.